package com.ybear.ybutils.utils.handler;

import android.os.Looper;
import android.os.Message;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public final class HandlerManage {
    @IntDef({ ErrorType.HANDLER_MESSAGE, ErrorType.DISPATCH_MESSAGE })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ErrorType {
        int HANDLER_MESSAGE = 0;
        int DISPATCH_MESSAGE = 1;
    }
    public interface OnErrorListener { void onError(@ErrorType int type); }
    public interface OnHandleMessageListener {
        void handleMessage(@NonNull Message msg);
    }

    private HandlerManage() {}

    public static Handler create(Looper looper, @Nullable Callback call) {
        return HANDLER.I.createHandler( looper, call );
    }

    public static Handler create(Looper looper) {
        return create( looper, null );
    }

    public static Handler create(@Nullable Callback l) {
        return create( Looper.getMainLooper(), l );
    }

    public static Handler create() {
        return create( (Callback) null );
    }

    public static Handler createForMyLooper(@Nullable Callback call) {
        return create( Looper.myLooper(), call );
    }

    public static Handler createForMyLooper() {
        return createForMyLooper( null );
    }

    public static Handler createForNotLooper(@Nullable Callback call) {
        return create( null, call );
    }

    public static Handler createForNotLooper() {
        return createForNotLooper( null );
    }

    private static final class HANDLER {
        private static final HandlerManage I = new HandlerManage();
    }

    private Handler createHandler(Looper looper, @Nullable Callback call) {
        OnlyHandler h = looper == null ? new OnlyHandler( call ) : new OnlyHandler( looper, call );
        return new Handler() {
            @Override
            public android.os.Handler getOsHandler() { return h; }

            @Override
            public Handler getHandler() { return this; }

            @Override
            public void setCallback(Callback call) { h.setCallback( call ); }

            @Override
            public boolean post(Runnable r) { return this.post( r, 0 ); }

            @Override
            public boolean post(Runnable r, long delayMillis) {
                if( delayMillis <= 0 ) return h.post( r );
                return h.postDelayed( r, delayMillis );
            }

            @Override
            public boolean postDelayed(Runnable r, long delayMillis) {
                return post( r, delayMillis );
            }

            @Override
            public boolean sendMessage(@NonNull Message msg) { return h.sendMessage( msg ); }
            @Override
            public boolean sendEmptyMessage(int what) { return h.sendEmptyMessage( what ); }
            @Override
            public boolean sendEmptyMessageDelayed(int what, long delayMillis) {
                return h.sendEmptyMessageDelayed( what, delayMillis );
            }
            @Override
            public boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
                return h.sendEmptyMessageAtTime( what, uptimeMillis );
            }
            @Override
            public boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
                return h.sendMessageDelayed( msg, delayMillis );
            }
            @Override
            public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
                return h.sendMessageAtTime( msg, uptimeMillis );
            }
            @Override
            public boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
                return h.sendMessageAtFrontOfQueue( msg );
            }

            @Override
            public void removeMessages(int what) { h.removeMessages( what ); }
            @Override
            public void removeMessages(int what, @Nullable Object object) {
                h.removeMessages( what, object );
            }
            @Override
            public void removeCallbacksAndMessages(@Nullable Object token) {
                h.removeCallbacksAndMessages( token );
            }

            @Override
            public void addOnErrorListener(OnErrorListener l) { h.addErrorListener( l ); }
            @Override
            public void removeErrorListener(OnErrorListener l) { h.removeErrorListener( l ); }

            @Override
            public void addHandleMessageListener(OnHandleMessageListener l) {
                h.addOnHandleMessageListener( l );
            }
            @Override
            public void removeOnHandleMessageListener(OnHandleMessageListener l) {
                h.removeOnHandleMessageListener( l );
            }
        };
    }

    /**
     * Handler
     */
    private static final class OnlyHandler extends android.os.Handler {
        @Nullable
        private WeakReference<com.ybear.ybutils.utils.handler.Callback> mWrListener;
        private List<OnErrorListener> mOnErrorList = new ArrayList<>();
        private List<OnHandleMessageListener> mOnHandleMessageList = new ArrayList<>();

        private OnlyHandler(@NonNull Looper looper,
                            @Nullable com.ybear.ybutils.utils.handler.Callback call) {
            super( looper );
            setCallback( call );
        }

        private OnlyHandler(@Nullable com.ybear.ybutils.utils.handler.Callback call) {
            setCallback( call );
        }

        void setCallback(com.ybear.ybutils.utils.handler.Callback call) {
            if( call == null ) return;
            mWrListener = new WeakReference<>( call );
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            com.ybear.ybutils.utils.handler.Callback call = getCall();
            if( call != null ) {
                call.handleMessage( msg );
                handle( msg );
            }else {
                error( ErrorType.HANDLER_MESSAGE );
            }
        }

        private void handle(Message msg) {
            if( mOnHandleMessageList.size() == 0 ) return;
            for (OnHandleMessageListener l : mOnHandleMessageList) {
                if( l != null ) l.handleMessage( msg );
            }
        }

        @Override
        public void dispatchMessage(@NonNull Message msg) {
            super.dispatchMessage(msg);
            com.ybear.ybutils.utils.handler.Callback call = getCall();
            if( call != null ) {
                call.dispatchMessage( msg );
            }else {
                error( ErrorType.DISPATCH_MESSAGE );
            }
        }

        private void error(@ErrorType int type) {
            if( mOnErrorList.size() == 0 ) return;
            for (OnErrorListener l : mOnErrorList) {
                if( l != null ) l.onError( type );
            }
        }

        private com.ybear.ybutils.utils.handler.Callback getCall() {
            if( mWrListener == null ) return null;
            return mWrListener.get();
        }

        void addErrorListener(OnErrorListener l) {
            if( !mOnErrorList.contains( l ) ) mOnErrorList.add( l );
        }
        void removeErrorListener(OnErrorListener l) { if( l != null ) mOnErrorList.remove( l ); }

        void addOnHandleMessageListener(OnHandleMessageListener l) {
            if( !mOnHandleMessageList.contains( l ) ) mOnHandleMessageList.add( l );
        }
        void removeOnHandleMessageListener(OnHandleMessageListener l) {
            mOnHandleMessageList.remove( l );
        }
    }
}